﻿////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// <copyright>Copyright 2008-2011 Andreas Huber Doenni</copyright>
// Distributed under the Microsoft Public License (Ms-PL).
// See accompanying file License.txt or copy at http://mews.codeplex.com/license.
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

namespace Mews
{
    using System;

    /// <summary>Represents a very simple state machine that forwards processing of events to the method that
    /// was last set with <see cref="StateMachine{T, U}.State"/>.</summary>
    /// <typeparam name="TEvent">The type of the events to process.</typeparam>
    /// <typeparam name="TResult">The type of the result returned by <see cref="ProcessEvent"/>.</typeparam>
    /// <remarks>A constructor accepting a <see cref="Func{T, U}"/> parameter was deliberately not added because a
    /// subclass constructor cannot pass a non-static member function to the base class constructor it is calling.
    /// </remarks>
    internal abstract class StateMachine<TEvent, TResult>
    {
        private Func<TEvent, TResult> state;

        ////////////////////////////////////////////////////////////////////////////////////////////////////////////////

        /// <summary>Processes the event with the method that was last set through
        /// <see cref="StateMachine{T, U}.State"/>.</summary>
        /// <exception cref="NullReferenceException"><see cref="StateMachine{T, U}.State"/> has never been set or was
        /// set to a <c>null</c>.
        /// </exception>
        public TResult ProcessEvent(TEvent ev)
        {
            return this.State(ev);
        }

        ////////////////////////////////////////////////////////////////////////////////////////////////////////////////

        /// <summary>Gets or sets the state.</summary>
        protected Func<TEvent, TResult> State
        {
            get { return this.state; }
            set { this.state = value; }
        }
    }
}
